package com.example.xd.defaultcall.test;

import android.content.Context;

import androidx.annotation.NonNull;
import androidx.collection.SimpleArrayMap;

/**
 * @auther XuDan on 2020/6/29.
 */
public class DialpadCharMappings {

    /** The character mapping for the Latin alphabet (the default mapping) */
    private static class Latin {
        private static final String[] KEY_TO_CHARS = {
                "+" /* 0 */,
                "" /* 1 */,
                "ABC" /* 2 */,
                "DEF" /* 3 */,
                "GHI" /* 4 */,
                "JKL" /* 5 */,
                "MNO" /* 6 */,
                "PQRS" /* 7 */,
                "TUV" /* 8 */,
                "WXYZ" /* 9 */,
                "" /* * */,
                "" /* # */,
        };

        private static final SimpleArrayMap<Character, Character> CHAR_TO_KEY =
                getCharToKeyMap(KEY_TO_CHARS);
    }

    /** The character mapping for the Bulgarian alphabet */
    private static class Bul {
        private static final String[] KEY_TO_CHARS = {
                "" /* 0 */,
                "" /* 1 */,
                "АБВГ" /* 2 */,
                "ДЕЖЗ" /* 3 */,
                "ИЙКЛ" /* 4 */,
                "МНО" /* 5 */,
                "ПРС" /* 6 */,
                "ТУФХ" /* 7 */,
                "ЦЧШЩ" /* 8 */,
                "ЪЬЮЯ" /* 9 */,
                "" /* * */,
                "" /* # */,
        };

        private static final SimpleArrayMap<Character, Character> CHAR_TO_KEY =
                getCharToKeyMap(KEY_TO_CHARS);
    }

    /** The character mapping for the Russian alphabet */
    private static class Rus {
        private static final String[] KEY_TO_CHARS = {
                "" /* 0 */,
                "" /* 1 */,
                "АБВГ" /* 2 */,
                "ДЕЁЖЗ" /* 3 */,
                "ИЙКЛ" /* 4 */,
                "МНОП" /* 5 */,
                "РСТУ" /* 6 */,
                "ФХЦЧ" /* 7 */,
                "ШЩЪЫ" /* 8 */,
                "ЬЭЮЯ" /* 9 */,
                "" /* * */,
                "" /* # */,
        };

        private static final SimpleArrayMap<Character, Character> CHAR_TO_KEY =
                getCharToKeyMap(KEY_TO_CHARS);
    }

    /** The character mapping for the Ukrainian alphabet */
    private static class Ukr {
        private static final String[] KEY_TO_CHARS = {
                "" /* 0 */,
                "" /* 1 */,
                "АБВГҐ" /* 2 */,
                "ДЕЄЖЗ" /* 3 */,
                "ИІЇЙКЛ" /* 4 */,
                "МНОП" /* 5 */,
                "РСТУ" /* 6 */,
                "ФХЦЧ" /* 7 */,
                "ШЩ" /* 8 */,
                "ЬЮЯ" /* 9 */,
                "" /* * */,
                "" /* # */,
        };

        private static final SimpleArrayMap<Character, Character> CHAR_TO_KEY =
                getCharToKeyMap(KEY_TO_CHARS);
    }

    // A map in which each key is an ISO 639-2 language code and the corresponding value is a
    // character-key map.
    private static final SimpleArrayMap<String, SimpleArrayMap<Character, Character>>
            CHAR_TO_KEY_MAPS = new SimpleArrayMap<>();

    // A map in which each key is an ISO 639-2 language code and the corresponding value is an array
    // defining a key-characters map.
    private static final SimpleArrayMap<String, String[]> KEY_TO_CHAR_MAPS = new SimpleArrayMap<>();

    static {
        CHAR_TO_KEY_MAPS.put("bul", Bul.CHAR_TO_KEY);
        CHAR_TO_KEY_MAPS.put("rus", Rus.CHAR_TO_KEY);
        CHAR_TO_KEY_MAPS.put("ukr", Ukr.CHAR_TO_KEY);

        KEY_TO_CHAR_MAPS.put("bul", Bul.KEY_TO_CHARS);
        KEY_TO_CHAR_MAPS.put("rus", Rus.KEY_TO_CHARS);
        KEY_TO_CHAR_MAPS.put("ukr", Ukr.KEY_TO_CHARS);
    }

    /**
     * Returns the character-key map of the ISO 639-2 language code of the 1st language preference or
     * null if no character-key map for the language code is defined.
     */
    public static SimpleArrayMap<Character, Character> getCharToKeyMap(@NonNull Context context) {
        return CHAR_TO_KEY_MAPS.get(CompatUtils.getLocale(context).getISO3Language());
    }

    /**
     * Returns the character-key map of the provided ISO 639-2 language code.
     *
     * <p>Note: this method is for implementations of {@link
     * com.android.dialer.smartdial.map.SmartDialMap} only. {@link #getCharToKeyMap(Context)} should
     * be used for all other purposes.
     *
     * <p>It is the caller's responsibility to ensure the language code is valid and a character
     * mapping is defined for that language. Otherwise, an exception will be thrown.
     */
    public static SimpleArrayMap<Character, Character> getCharToKeyMap(String languageCode) {
        SimpleArrayMap<Character, Character> charToKeyMap = CHAR_TO_KEY_MAPS.get(languageCode);

        return Assert.isNotNull(
                charToKeyMap, "No character mappings can be found for language code '%s'", languageCode);
    }

    /** Returns the default character-key map (the one that uses the Latin alphabet). */
    public static SimpleArrayMap<Character, Character> getDefaultCharToKeyMap() {
        return Latin.CHAR_TO_KEY;
    }

    /**
     * Returns the key-characters map of the given ISO 639-2 language code of the 1st language
     * preference or null if no key-characters map for the language code is defined.
     */
    static String[] getKeyToCharsMap(@NonNull Context context) {
        return KEY_TO_CHAR_MAPS.get(CompatUtils.getLocale(context).getISO3Language());
    }

    /** Returns the default key-characters map (the one that uses the Latin alphabet). */
    public static String[] getDefaultKeyToCharsMap() {
        return Latin.KEY_TO_CHARS;
    }

    /**
     * Given a array representing a key-characters map, return its reverse map.
     *
     * <p>It is the caller's responsibility to ensure that
     *
     * <ul>
     *   <li>the array contains only 12 elements,
     *   <li>the 0th element ~ the 9th element are the mappings for keys "0" ~ "9",
     *   <li>the 10th element is for key "*", and
     *   <li>the 11th element is for key "#".
     * </ul>
     *
     * @param keyToChars An array representing a key-characters map. It must satisfy the conditions
     *     above.
     * @return A character-key map.
     */
    private static SimpleArrayMap<Character, Character> getCharToKeyMap(
            @NonNull String[] keyToChars) {
        Assert.checkArgument(keyToChars.length == 12);

        SimpleArrayMap<Character, Character> charToKeyMap = new SimpleArrayMap<>();

        for (int keyIndex = 0; keyIndex < keyToChars.length; keyIndex++) {
            String chars = keyToChars[keyIndex];

            for (int j = 0; j < chars.length(); j++) {
                char c = chars.charAt(j);
                if (Character.isAlphabetic(c)) {
                    charToKeyMap.put(Character.toLowerCase(c), getKeyChar(keyIndex));
                }
            }
        }

        return charToKeyMap;
    }

    /** Given a key index of the dialpad, returns the corresponding character. */
    private static char getKeyChar(int keyIndex) {
        Assert.checkArgument(0 <= keyIndex && keyIndex <= 11);

        switch (keyIndex) {
            case 10:
                return '*';
            case 11:
                return '#';
            default:
                return (char) ('0' + keyIndex);
        }
    }
}
